package ua.lviv.franko.mlsFunctions.twoDimension;

import java.util.ArrayList;

import org.jzy3d.maths.Range;
import org.jzy3d.plot3d.builder.Mapper;

import ua.lviv.franko.integration.IFunction2D;
import ua.lviv.franko.mlsFunctions.oneDimension.weightFunctions.CubicSpline;
import ua.lviv.franko.mlsFunctions.twoDimension.weightFunctions.IWeightFunction2D;
import ua.lviv.franko.mlsFunctions.twoDimension.weightFunctions.SquareSupport;
import ua.lviv.franko.solvers.twoDimention.LinearRectangularElement;
import ua.lviv.franko.triangulation.SaveStructures.Node;
import ua.lviv.franko.visualisation.Visualise3D;

public class BaseFunctionForEnrichment extends BaseFunctionCoupled implements IFunction2D {

	protected LinearRectangularElement	elementForEnrichment;

	public BaseFunctionForEnrichment(int PolinomialDegree, Particle xi, IWeightFunction2D func, LinearRectangularElement elementForEnrichment) {
		super(PolinomialDegree, xi, func, null);
		this.elementForEnrichment = elementForEnrichment;
	}

	@Override
	public double[] calculateDerivatyXFEM(double x, double y) {
		ArrayList<Double> vals = this.getBaseVector(elementForEnrichment.getA().x, elementForEnrichment.getA().y,
				new Particle(elementForEnrichment.getA().x, elementForEnrichment.getA().y, 0.0));
		double[] res = new double[vals.size()];
		for (int i = 0; i < res.length; i++) {
			res[i] = elementForEnrichment.N1.calculateDerivatyX(x, y) * vals.get(i);
		}

		vals = this.getBaseVector(elementForEnrichment.getB().x, elementForEnrichment.getB().y, new Particle(elementForEnrichment.getB().x, elementForEnrichment.getB().y, 0.0));
		for (int i = 0; i < res.length; i++) {
			res[i] += elementForEnrichment.N2.calculateDerivatyX(x, y) * vals.get(i);
		}

		vals = this.getBaseVector(elementForEnrichment.getC().x, elementForEnrichment.getC().y, new Particle(elementForEnrichment.getC().x, elementForEnrichment.getC().y, 0.0));
		for (int i = 0; i < res.length; i++) {
			res[i] += elementForEnrichment.N3.calculateDerivatyX(x, y) * vals.get(i);
		}

		vals = this.getBaseVector(elementForEnrichment.getD().x, elementForEnrichment.getD().y, new Particle(elementForEnrichment.getD().x, elementForEnrichment.getD().y, 0.0));
		for (int i = 0; i < res.length; i++) {
			res[i] += elementForEnrichment.N4.calculateDerivatyX(x, y) * vals.get(i);
		}

		return res;
	}

	@Override
	public double[] calculateDerivatyYFEM(double x, double y) {
		ArrayList<Double> vals = this.getBaseVector(elementForEnrichment.getA().x, elementForEnrichment.getA().y,
				new Particle(elementForEnrichment.getA().x, elementForEnrichment.getA().y, 0.0));
		double[] res = new double[vals.size()];
		for (int i = 0; i < res.length; i++) {
			res[i] = elementForEnrichment.N1.calculateDerivatyY(x, y) * vals.get(i);
		}

		vals = this.getBaseVector(elementForEnrichment.getB().x, elementForEnrichment.getB().y, new Particle(elementForEnrichment.getB().x, elementForEnrichment.getB().y, 0.0));
		for (int i = 0; i < res.length; i++) {
			res[i] += elementForEnrichment.N2.calculateDerivatyY(x, y) * vals.get(i);
		}

		vals = this.getBaseVector(elementForEnrichment.getC().x, elementForEnrichment.getC().y, new Particle(elementForEnrichment.getC().x, elementForEnrichment.getC().y, 0.0));
		for (int i = 0; i < res.length; i++) {
			res[i] += elementForEnrichment.N3.calculateDerivatyY(x, y) * vals.get(i);
		}

		vals = this.getBaseVector(elementForEnrichment.getD().x, elementForEnrichment.getD().y, new Particle(elementForEnrichment.getD().x, elementForEnrichment.getD().y, 0.0));
		for (int i = 0; i < res.length; i++) {
			res[i] += elementForEnrichment.N4.calculateDerivatyY(x, y) * vals.get(i);
		}

		return res;
	}

	@Override
	public double[] calculateFEM(double x, double y) {
		ArrayList<Double> vals = this.getBaseVector(elementForEnrichment.getA().x, elementForEnrichment.getA().y,
				new Particle(elementForEnrichment.getA().x, elementForEnrichment.getA().y, 0.0));
		double[] res = new double[vals.size()];
		for (int i = 0; i < res.length; i++) {
			res[i] = elementForEnrichment.N1.calculate(x, y) * vals.get(i);
		}

		vals = this.getBaseVector(elementForEnrichment.getB().x, elementForEnrichment.getB().y, new Particle(elementForEnrichment.getB().x, elementForEnrichment.getB().y, 0.0));
		for (int i = 0; i < res.length; i++) {
			res[i] += elementForEnrichment.N2.calculate(x, y) * vals.get(i);
		}

		vals = this.getBaseVector(elementForEnrichment.getC().x, elementForEnrichment.getC().y, new Particle(elementForEnrichment.getC().x, elementForEnrichment.getC().y, 0.0));
		for (int i = 0; i < res.length; i++) {
			res[i] += elementForEnrichment.N3.calculate(x, y) * vals.get(i);
		}

		vals = this.getBaseVector(elementForEnrichment.getD().x, elementForEnrichment.getD().y, new Particle(elementForEnrichment.getD().x, elementForEnrichment.getD().y, 0.0));
		for (int i = 0; i < res.length; i++) {
			res[i] += elementForEnrichment.N4.calculate(x, y) * vals.get(i);
		}

		return res;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ArrayList<Particle> nodes = new ArrayList<Particle>();
		// параметри області:
		double ax = 0, bx = 1, ay = 0, by = 1;

		int n = 4, m = 4;

		double hx = (bx - ax) / (double) n, hy = (by - ay) / (double) m;

		// вузли+функції:
		for (int i = 0; i <= n; i++) {
			for (int j = 0; j <= m; j++) {
				Particle p = new Particle(ax + i * hx, ay + j * hy, 2.2 * hx);
				nodes.add(p);
			}
		}
		final BaseFunctionForEnrichment ff = new BaseFunctionForEnrichment(2, new Particle(0.250, 0.5, 2.2 * hx), new SquareSupport(new CubicSpline()),
				new LinearRectangularElement(0, 1, 2, 3, new Node(0.0, 0.0, true, 0), new Node(1.0, 0.0, true, 1), new Node(1.0, 1.0, true, 2), new Node(0.0, 1.0, true, 3), null));
		ff.setNodeList(nodes);
		Visualise3D.show(new Mapper() {
			@Override
			public double f(double x, double y) {
				// return ff.calculateDerivatyX(x, y);//(x, y);
				return ff.calculate(x, y);
			}
		}, new Range(-1.0, 1.0), new Range(-1.0, 1.0));

	}

}
